package com.jamal2362.apktool.util;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.PopupMenu;

import com.jamal2362.apktool.MainActivity;
import com.jamal2362.apktool.R;
import com.jamal2362.apktool.fragment.files.Refreshable;
import com.jamal2362.apktool.task.DecodeTask;
import com.jamal2362.apktool.task.ExtractSplit;
import com.jamal2362.apktool.task.ExtractTask;
import com.jamal2362.apktool.task.VerifyTask;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class MUtil {
	public static int spAsPx(Context c, float dp) {
		return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, c.getResources().getDisplayMetrics());
	}

	public static int spAsPx(Context c, int dp) {
		return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, c.getResources().getDisplayMetrics());
	}

	public static String getSign(AppCompatActivity mActivity) {
		try {
			Signature sig = mActivity.getPackageManager().getPackageInfo(mActivity.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];
			return String.valueOf(sig.hashCode());
		} catch (Exception e) {
			return null;
		}
		// return "1924304562"; // НЕ ТРОГАТЬ!
	}

	public static boolean strt(AppCompatActivity act) {
		return getSign(act).equals(gk());
	}

	public static String gk() {
		return fromCharCode(49, 57, 50, 52, 51, 48, 52, 53, 54, 50);
	}

	public static String fromCharCode(int... codePoints) {
		StringBuilder builder = new StringBuilder(codePoints.length);
		for (int codePoint : codePoints) {
			builder.append(Character.toChars(codePoint));
		}
		return builder.toString();
	}

	public static void createDialog(Context ctx, String message, final Runnable posClick) {
		createDialog(ctx, message, R.string.ok, posClick);
	}

	public static void createDialog(Context ctx, String message, int pbutton, final Runnable posClick) {
		new MDialog(ctx, message).cancelable(false).positive(pbutton, posClick).negative(R.string.cancel).show();
	}

	public static void showAppDetails(final Context context, final File file, final PackageInfo pkg, final PackageManager pm) {
		if (file == null && (pkg == null || pm == null)) {
			TextUtil.st(context, context.getString(R.string.error));
			return;
		}
		LayoutInflater inflater = LayoutInflater.from(context);
		View view = inflater.inflate(R.layout.search_progress, null);
		TextView tview = view.findViewById(R.id.searchprogressTextView1);
		tview.setText(R.string.mplease_wait);
		final AlertDialog progress = new AlertDialog.Builder(context)
			.setView(view)
			.setCancelable(false)
			.create();
		progress.show();
		Runnable showDetails = new Runnable()
		{
			@Override
			public void run() {
				if (pm == null || pkg == null) {
					try {
						String path = file.getAbsolutePath();
						String realPath = null;
						String name = file.getName().toLowerCase();
						if (name.endsWith(".apks") || name.endsWith(".xapk")) {
							ZipFile zip = new ZipFile(file);
							Enumeration e = zip.entries();
							int count = 0;
							byte[] buffer = new byte[2048];
							while (e.hasMoreElements()) {
								ZipEntry entry = (ZipEntry) e.nextElement();
								if (entry.getName().toLowerCase().endsWith(".apk") && !entry.getName().contains(File.separator)) {
									final File temp = File.createTempFile("A_TempApkIT", ".tmp", new File(Settings.appCacheDir));
									InputStream is = zip.getInputStream(entry);
									FileOutputStream fos = new FileOutputStream(temp);
									try {
										while ((count = is.read(buffer)) != -1)
											fos.write(buffer, 0, count);
									} finally {
										is.close();
										fos.close();
									}
									Apkinfo apkInfo = new Apkinfo(context, temp.getAbsolutePath());
									if (!apkInfo.isValid() || apkInfo.icon() == null) {
										temp.delete();
										continue;
									} else {
										realPath = file.getAbsolutePath();
										path = temp.getAbsolutePath();
									}
								}
							}
						}
						PackageManager pmanager = context.getPackageManager();
						PackageInfo packageInfo = pmanager.getPackageArchiveInfo(path, PackageManager.GET_SIGNATURES);
						packageInfo.applicationInfo.sourceDir = path;
						packageInfo.applicationInfo.publicSourceDir = path;
						showAppDetails(context, packageInfo, pmanager, realPath);
					} catch (Exception e) {
						TextUtil.st(context, context.getString(R.string.failed_open, file.getName()));
						e.printStackTrace();
					}
				} else {
					showAppDetails(context, pkg, pm, null);
				}
				progress.cancel();
			}
		};
		new Handler().postDelayed(showDetails, 100);
	}

	private static void showAppDetails(final Context context, final PackageInfo pkg, final PackageManager pm, String path) {
		int marg = spAsPx(context, 10);
		LayoutParams param = new LayoutParams(
			LayoutParams.MATCH_PARENT,      
			LayoutParams.WRAP_CONTENT
		);
		param.setMargins(marg, marg / 2, marg, 0);
		LinearLayout view = new LinearLayout(context);
		view.setLayoutParams(param);
		view.setOrientation(LinearLayout.VERTICAL);
		final ApplicationInfo info = pkg.applicationInfo;
		final File[] apks = MUtil.getApkFiles(pkg);
		final Manifest mf = new Manifest(apks[0]);
		int minsdk, targetsdk;
		boolean isSplitRequired;
		try {
			minsdk = mf.getMinSdkVersion();
			targetsdk = mf.getTargetSdkVersion();
			isSplitRequired = mf.isSplitRequired();
		} catch (Exception e) {
			minsdk = targetsdk = 0;
			isSplitRequired = false;
		}
		final boolean[] tempDelete = {true};
		final File[] realFile = new File[1];
		if (path == null) {
			tempDelete[0] = false;
			realFile[0] = apks[0];
			path = apks[0].getParent();
		} else {
			realFile[0] = new File(path);
			path = realFile[0].getParent();
		}
		final boolean install = (FileUtils.isInstalledApk(context, apks[0]) && !tempDelete[0]);
		final String[] installpkg = FileUtils.packageInstalledInfo(context, pkg, pm);
		String humSize = "";
		if (!tempDelete[0]) {
			long fullSize = 0;
			for (int i = 0; i < apks.length; i++) {
				long size = FileUtils.getFileSize(apks[i]);
				fullSize += size;
				if (i > 0)
					humSize += " + ";
				humSize += FileUtils.humanReadableByteCount(size, false);
			}
			if (apks.length > 1) {
				humSize += " = " + FileUtils.humanReadableByteCount(fullSize, false);
			}
		} else {
			humSize = FileUtils.humanReadableByteCount(realFile[0].length(), false);
		}

		LayoutInflater inflater = LayoutInflater.from(context);
		view.addView(createLine(context, inflater, context.getString(R.string.version_app) , pkg.versionName), param);
		view.addView(createLine(context, inflater, context.getString(R.string.vcode_app) , pkg.versionCode + ""), param);
		if (installpkg != null && !install) {
			view.addView(createLine(context, inflater, context.getString(R.string.inst_ver) , installpkg[0]), param);
			view.addView(createLine(context, inflater, context.getString(R.string.sign_match) , installpkg[1]), param);
		}
		if (install || isSplitRequired) {
			int yn = ((apks.length > 1 || isSplitRequired) ? R.string.split : R.string.no);
			view.addView(createLine(context, inflater, context.getString(R.string.split) , context.getString(yn).toLowerCase()), param);
		}
		view.addView(createLine(context, inflater, context.getString(R.string.pname_app) , info.packageName), param);
		if (minsdk > 0)
			view.addView(createLine(context, inflater, context.getString(R.string.mapp_minsdk) , minsdk + " (" + getSDK(minsdk) + ")"), param);
		if (targetsdk > 0)
			view.addView(createLine(context, inflater, context.getString(R.string.mapp_targetsdk) , targetsdk + " (" + getSDK(targetsdk) + ")"), param);
		view.addView(createLine(context, inflater, context.getString(R.string.path_app) , path, new Runnable() {
							 @Override
							 public void run() {
								 MainActivity ma = MainActivity.INSTANCE;
								 if (ma != null)
									 ma.showPath(realFile[0].getParentFile());
								 else
									 TextUtil.st(context, context.getString(R.string.failed_open, realFile[0].getParentFile().getAbsolutePath()));
							 }
						 }), param);
		if (install && info.uid >= 0) {
			view.addView(createLine(context, inflater, context.getString(R.string.data_dir) , info.dataDir), param);
			view.addView(createLine(context, inflater, context.getString(R.string.app_uid) , String.valueOf(info.uid)), param);
		}
		view.addView(createLine(context, inflater, context.getString(R.string.size_label) , humSize), param);

		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setTitle(info.loadLabel(pm)).
			setIcon(info.loadIcon(pm)).
			setView(view);
		if (install) {
			builder.setPositiveButton(R.string.extract, new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface d, int p) {
						try {
							String appFullLabel = info.loadLabel(pm) + "_v" + pkg.versionName + "(" + pkg.versionCode + ")";
							if (apks.length > 1) {
								MUtil.extractApksDialog(context, apks, TextUtil.replaceIllegal(appFullLabel), appFullLabel);
							} else {
								new ExtractTask(context, TextUtil.replaceIllegal(appFullLabel) + ".apk", null).execute(apks);
							}
						} catch (Exception e) {
							TextUtil.st(context, context.getString(R.string.errorf, e.getMessage()));
						}
						d.cancel();
					}
				});
		} else {
			builder.setPositiveButton(R.string.install, new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface d, int p) {
						if (tempDelete[0]) {
							FileUtils.openApks(context, realFile[0], null, 1);
						} else {
							FileUtils.preInstall(context, apks[0]);
						}
						d.cancel();
					}
				});
		}
		builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
				@Override
				public void onCancel(DialogInterface p1) {
					if (tempDelete[0]) {
						apks[0].delete();
					}
				}
			});
		builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener()
			{
				public void onClick(DialogInterface d, int p) {
					d.cancel();
				}
			});
		builder.setNeutralButton(R.string.mshow_more_options, null);
		final AlertDialog dialog = builder.create();
		dialog.setOnShowListener(new DialogInterface.OnShowListener()
			{
				@Override
				public void onShow(DialogInterface p1) {
					Button neutral = dialog.getButton(AlertDialog.BUTTON_NEUTRAL);
					// neutral.setEnabled(!tempDelete[0]);
					neutral.setOnClickListener(new View.OnClickListener() {
							@Override
							public void onClick(View v) {
								PopupMenu menu = new PopupMenu(context, v);
								int mid = 1300;
								if (!tempDelete[0]) {
									MenuItem decode = menu.getMenu().add(0, mid++, 0, context.getString(R.string.decompile));
									decode.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												MUtil.decode(context, null, apks, info.loadLabel(pm).toString());
												return true;
											}
										});
									MenuItem verify = menu.getMenu().add(0, mid++, 0, context.getString(R.string.verify));
									verify.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												new VerifyTask(context).execute(apks[0]);
												return true;
											}
										});
								} else {
									MenuItem installs = menu.getMenu().add(0, mid++, 0, context.getString(R.string.install_sign));
									installs.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												FileUtils.openApks(context, realFile[0], null, 2);
												dialog.cancel();
												return true;
											}
										});
									MenuItem antisplit = menu.getMenu().add(0, mid++, 0, context.getString(R.string.mantisplit));
									antisplit.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												FileUtils.openApks(context, realFile[0], null, 0);
												dialog.cancel();
												return true;
											}
										});
								}
								if (installpkg != null) {
									MenuItem settings = menu.getMenu().add(0, mid++, 0, context.getString(R.string.settings));
									settings.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												goToSettings(context, info.packageName);
												return true;
											}
										});
									MenuItem launch = menu.getMenu().add(0, mid++, 0, context.getString(R.string.launch_app));
									launch.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												launchApp(context, info.packageName);
												return true;
											}
										});
									MenuItem delete = menu.getMenu().add(0, mid++, 0, context.getString(R.string.delete));
									delete.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
										{
											@Override
											public boolean onMenuItemClick(MenuItem m) {
												deleteApp(context, info.packageName);
												return true;
											}
										});
								}
								MenuItem gplay = menu.getMenu().add(0, mid++, 0, context.getString(R.string.gplay));
								gplay.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
									{
										@Override
										public boolean onMenuItemClick(MenuItem m) {
											openMarket(context, info.packageName);
											return true;
										}
									});
								menu.show();
							}
						});
				}
			});
		dialog.show();
	}

	public static void preFileDetails(final Context context, final File file) {
		if (file == null) {
			TextUtil.st(context, context.getString(R.string.error));
			return;
		}
		LayoutInflater inflater = LayoutInflater.from(context);
		View view = inflater.inflate(R.layout.search_progress, null);
		TextView tview = view.findViewById(R.id.searchprogressTextView1);
		tview.setText(R.string.mplease_wait);
		final AlertDialog progress = new AlertDialog.Builder(context)
			.setView(view)
			.setCancelable(false)
			.create();
		progress.show();
		Runnable showDetails = new Runnable() {
			@Override
			public void run() {
				showFileDetails(context, file);
				progress.cancel();
			}
		};
		new Handler().postDelayed(showDetails, 100);
	}

	private static void showFileDetails(final Context context, final File file) {
		int marg = spAsPx(context, 10);
		LayoutParams param = new LayoutParams(
			LayoutParams.MATCH_PARENT,      
			LayoutParams.WRAP_CONTENT
		);
		param.setMargins(marg, marg / 2, marg, 0);
		LinearLayout view = new LinearLayout(context);
		view.setLayoutParams(param);
		view.setOrientation(LinearLayout.VERTICAL);
		final long size = FileUtils.getFileSize(file);
		String humSize = FileUtils.humanReadableByteCount(size, false);
		LayoutInflater inflater = LayoutInflater.from(context);
		view.addView(createLine(context, inflater, context.getString(R.string.name) , file.getName(), new Runnable() {
							 @Override
							 public void run() {
								 TextUtil.setClipboard(context, file.getAbsolutePath());
							 }
						 }), param);
		view.addView(createLine(context, inflater, context.getString(R.string.path_app) , file.getParent()), param);
		view.addView(createLine(context, inflater, context.getString(R.string.size_label) , humSize, new Runnable() {
							 @Override
							 public void run() {
								 TextUtil.setClipboard(context, size + "");
							 }
						 }), param);
		view.addView(createLine(context, inflater, context.getString(R.string.modified) , TextUtil.dateFormat(file.lastModified())), param);
		if (file.isDirectory()) {
			try {
				view.addView(createLine(context, inflater, context.getString(R.string.total_foldersc), FileUtils.countOfFiles(context, file, true, true) + ""), param);
				view.addView(createLine(context, inflater, context.getString(R.string.total_filesc), FileUtils.countOfFiles(context, file, false, true) + ""), param);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			final String md5file = FileUtils.fileDigest(file.getAbsolutePath(), TextUtil.MD5);
			final String sha1file = FileUtils.fileDigest(file.getAbsolutePath(), TextUtil.SHA1);
			final String sha256file = FileUtils.fileDigest(file.getAbsolutePath(), TextUtil.SHA256);
			final String crc32file = Long.toHexString(FileUtils.fileCRC32(file.getAbsolutePath())).toLowerCase();
			String mime = FileUtils.getMimeType(Uri.fromFile(file).toString());
			if (mime != null && !TextUtils.isEmpty(mime)) {
				view.addView(createLine(context, inflater, "Mime-Type" , mime), param);
			}
			view.addView(createLine(context, inflater, TextUtil.MD5 , md5file), param);
			view.addView(createLine(context, inflater, TextUtil.SHA1 , sha1file), param);
			view.addView(createLine(context, inflater, TextUtil.SHA256 , sha256file), param);
			view.addView(createLine(context, inflater, TextUtil.CRC32 , crc32file), param);

			View checkView = inflater.inflate(R.layout.checksum, null);
			final TextView checkText = checkView.findViewById(R.id.checksumTextView1);
			checkText.setTextSize(TypedValue.COMPLEX_UNIT_SP, Settings.appFontSize);
			final EditText textSum = checkView.findViewById(R.id.checksumEditText1);
			final Button pasteButton = checkView.findViewById(R.id.checksumButton1);
			pasteButton.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View p1) {
						String clip = TextUtil.readFromClipboard(context);
						if (clip != null)
							textSum.setText(clip);
					}
				});
			textSum.addTextChangedListener(new TextWatcher(){
					@Override
					public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) {
						// TODO: Implement this method
					}
					@Override
					public void onTextChanged(CharSequence p1, int p2, int p3, int p4) {
						// TODO: Implement this method
					}
					@Override
					public void afterTextChanged(Editable p1) {
						String text = p1.toString().toLowerCase().trim();
						String title = context.getString(R.string.check_hash);
						if (TextUtils.isEmpty(text)) {
							checkText.setText(title);
							return;
						}
						int color = Color.RED;
						String result = context.getString(R.string.not_match);
						String matches = context.getString(R.string.matches);
						if (text.equals(md5file)) {
							color = Color.GREEN;
							result = TextUtil.MD5 + " " + matches;
						} else if (text.equals(sha1file)) {
							color = Color.GREEN;
							result = TextUtil.SHA1 + " " + matches;
						} else if (text.equals(sha256file)) {
							color = Color.GREEN;
							result = TextUtil.SHA256 + " " + matches;
						} else if (text.equals(crc32file)) {
							color = Color.GREEN;
							result = TextUtil.CRC32 + " " + matches;
						}
						SpannableString str = new SpannableString(title + ": " + result);
						str.setSpan(new ForegroundColorSpan(color), title.length() + 2, title.length() + result.length() + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
						str.setSpan(new StyleSpan(Typeface.BOLD), title.length() + 2, title.length() + result.length() + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
						checkText.setText(str);
					}
				});
			view.addView(checkView, param);
		}

		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setTitle(context.getString(R.string.properties) + " \"" + file.getName() + "\"").
			setView(view).
			setPositiveButton(R.string.close_cur, null).
			create().
			show();
	}

	public static View createLine(final Context c, LayoutInflater inflater, final String a, final String b) {
		return createLine(c, inflater, a, b, null);
	}

	public static View createLine(final Context context, LayoutInflater inflater, final String name, final String value, final Runnable longClick) {
		View view = inflater.inflate(R.layout.line_layout, null);
		TextView tvName = view.findViewById(R.id.linelayoutTextView1);
		TextView tvValue = view.findViewById(R.id.linelayoutTextView2);
		tvName.setText(name);
		tvValue.setText(value);
		tvName.setTextSize(TypedValue.COMPLEX_UNIT_SP, Settings.appFontSize);
		tvValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, Settings.appFontSize - 2);
		tvValue.setOnClickListener(new OnClickListener()
			{
				public void onClick(View v) {
					TextUtil.setClipboard(context, value);
				}
			});
		if (longClick != null) {
			tvValue.setOnLongClickListener(new OnLongClickListener()
				{
					@Override
					public boolean onLongClick(View p1) {
						longClick.run();
						return true;
					}
				});
		}
		return view;
	}

	public static void decode(final Context ctx, final Refreshable refresh, final File[] files, final String name) {
		final Button[] buttons = new Button[1];
		final LayoutInflater inflater = LayoutInflater.from(ctx);
		final View dview = inflater.inflate(R.layout.decompile, null);
		final CheckBox dres = dview.findViewById(R.id.decompileCheckBox2);
		final CheckBox ddex = dview.findViewById(R.id.decompileCheckBox3);
		dres.setChecked(Settings.getb(ctx, "dcode_rs", true));
		ddex.setChecked(Settings.getb(ctx, "dcode_dx", false));
		AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
		builder.setTitle(name);
		builder.setView(dview);
		builder.setNegativeButton(R.string.cancel, null);
		builder.setPositiveButton(R.string.decompile, new DialogInterface.OnClickListener()
			{
				@Override
				public void onClick(DialogInterface p1, int p2) {
					DecodeTask dtask = new DecodeTask(ctx, refresh, null);
					dtask.setDecodeRes(dres.isChecked());
					dtask.setDecodeDex(ddex.isChecked());
					Settings.setb(ctx, "dcode_rs", dres.isChecked());
					Settings.setb(ctx, "dcode_dx", ddex.isChecked());
					dtask.execute(files);
					p1.dismiss();
				}
			});
		View.OnClickListener checkClick = new OnClickListener()
		{
			@Override
			public void onClick(View p1) {
				if (buttons[0] != null) {
					buttons[0].setEnabled(dres.isChecked() || ddex.isChecked());
				}
			}
		};
		dres.setOnClickListener(checkClick);
		ddex.setOnClickListener(checkClick);
		final AlertDialog dialog = builder.create();
		dialog.setOnShowListener(new DialogInterface.OnShowListener() {
				@Override
				public void onShow(DialogInterface dialogInterface) {
					buttons[0] = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
					buttons[0].setEnabled(dres.isChecked() || ddex.isChecked());
				}
			});
		dialog.show();
	}

	public static void extractApksDialog(final Context ctx, final File[] apks, final String outApkName, final String title) {
		final Button[] button = new Button[1];
		final String[] items = new String[apks.length];
		final boolean [] checked = new boolean[apks.length];
		for (int i = 0 ; i <  apks.length; i++) {
			items[i] = apks[i].getName();
			checked[i] = true;
		}
		AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
		builder.setMultiChoiceItems(items, checked, new DialogInterface.OnMultiChoiceClickListener()
			{
				@Override
				public void onClick(DialogInterface p1, int p2, boolean p3) {
					checked[p2] = p3;
					for (int i = 0 ; i <  checked.length; i++) {
						if (checked[i]) {
							button[0].setEnabled(true);
							return;
						}
					}
					button[0].setEnabled(false);
				}
			});
		builder.setTitle(title);
		builder.setNegativeButton(R.string.cancel, null);
		builder.setPositiveButton(R.string.extract, new DialogInterface.OnClickListener()
			{
				@Override
				public void onClick(DialogInterface p1, int p2) {
					List<File> files = new ArrayList<File>();
					for (int i = 0 ; i <  checked.length; i++) {
						if (checked[i]) {
							files.add(apks[i]);
						}
					}
					if (files.isEmpty())
						return;
					File[] exapks = files.toArray(new File[files.size()]);
					if (exapks.length > 1) {
						new ExtractSplit(ctx, outApkName, null).execute(exapks);
					} else {
						new ExtractTask(ctx, outApkName + "_" + exapks[0].getName(), null).execute(exapks);
					}
				}
			});
		final AlertDialog dialog = builder.create();
		dialog.setOnShowListener(new DialogInterface.OnShowListener()
			{
				@Override
				public void onShow(DialogInterface p1) {
					button[0] = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
				}
			});
		dialog.show();
	}

	public static void goToSettings(Context c, String p) {
		try {
			Intent myAppSettings = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + p));
			myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
			myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			c.startActivity(myAppSettings);
		} catch (Exception e) {
			TextUtil.st(c, c.getString(R.string.failed_openset));
		}
	}

	public static String strJoin(String[] arr, String sep) {
		StringBuilder sbStr = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			if (i > 0)
				sbStr.append(sep);
			sbStr.append(arr[i]);
		}
		return sbStr.toString();
	}

	public static String strJoin(List<String> arr, String sep) {
		StringBuilder sbStr = new StringBuilder();
		for (int i = 0; i < arr.size(); i++) {
			if (i > 0)
				sbStr.append(sep);
			sbStr.append(arr.get(i));
		}
		return sbStr.toString();
	}

	public static void toggledScreenOn(AppCompatActivity mActivity, boolean screenon) {
		if (screenon) {
			mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		} else {
			mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		}
	}

	public static File[] getApkFiles(PackageInfo pkg) {
		ApplicationInfo applicationInfo = pkg.applicationInfo;
		List<File> apkFiles = new ArrayList<>();
		apkFiles.add(0, new File(applicationInfo.sourceDir));
		if (Build.VERSION.SDK_INT >= 21) {
			if (applicationInfo.splitSourceDirs != null) {
				for (String splitPath : applicationInfo.splitSourceDirs)
					apkFiles.add(new File(splitPath));
			}
		}
		File[] res = new File[apkFiles.size()];
		for (int i = 0; i < apkFiles.size(); i++) {
			res[i] = apkFiles.get(i);
		}
		return res;
	}

	public static void openUrl(Context act, String u) {
		try {
			Intent i = new Intent(Intent.ACTION_VIEW);
			i.setData(Uri.parse(u));
			act.startActivity(i);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String getCountry(Context context) {
		String lang = Settings.gets(context.getApplicationContext(), "lang", "default");	
		if (lang.equals("default")) {
			lang = context.getApplicationContext().getResources().getConfiguration().locale.getCountry().toLowerCase();
			if (lang == null || lang.equals("")) {
				TelephonyManager tm = (TelephonyManager)context.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
				lang = tm.getNetworkCountryIso().toLowerCase();
			}
		}
		return lang;
	}

	public static void launchApp(Context ctx, String pn) {
		try {
			PackageManager pm = ctx.getPackageManager();
			Intent launchIntent = pm.getLaunchIntentForPackage(pn);
			if (launchIntent != null)
				ctx.startActivity(launchIntent);
			else
				TextUtil.st(ctx, ctx.getString(R.string.launch_fail));
		} catch (Exception e) {
			TextUtil.st(ctx, ctx.getString(R.string.error));
		}
	}

	public static void deleteApp(Context ctx, String pn) {
		Intent intent = new Intent(Intent.ACTION_DELETE);
		intent.setData(Uri.parse("package:" + pn));
		ctx.startActivity(intent);
	}

	public static void openMarket(Context context, String packageName) {
		try {
			context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName)));
		} catch (Exception e) {
			context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + packageName)));
		}
	}

	public static String getSDK(int i) {
		switch (i) {
			case 1:
				return "Android 1.0";
			case 2:
				return "Android 1.1";
			case 3:
				return "Android 1.5";
			case 4:
				return "Android 1.6";
			case 5:
				return "Android 2.0";
			case 6:
				return "Android 2.0.1";
			case 7:
				return "Android 2.1.x";
			case 8:
				return "Android 2.2.x";
			case 9:
				return "Android 2.3/2.3.1/2.3.2";
			case 10:
				return "Android 2.3.3/2.3.4";
			case 11:
				return "Android 3.0.x";
			case 12:
				return "Android 3.1.x";
			case 13:
				return "Android 3.2";
			case 14:
				return "Android 4.0/4.0.1/4.0.2";
			case 15:
				return "Android 4.0.3/4.0.4";
			case 16:
				return "Android 4.1/4.1.1";
			case 17:
				return "Android 4.2/4.2.2";
			case 18:
				return "Android 4.3";
			case 19:
				return "Android 4.4";
			case 20:
				return "Android 4.4W";
			case 21:
				return "Android 5.0";
			case 22:
				return "Android 5.1.1";
			case 23:
				return "Android 6.0";
			case 24:
				return "Android 7.0";
			case 25:
				return "Android 7.1/7.1.1";
			case 26:
				return "Android 8.0";
			case 27:
				return "Android 8.1";
			case 28:
				return "Android 9";
			case 29:
				return "Android 10";
			case 30:
				return "Android 11";
			default:
				return "Android Unknow";
		}
	}
}
